#include "facedetect.h"

FaceDetect::~FaceDetect() {

}

//初始化人脸识别指针
std::shared_ptr<FaceDetect> FaceDetect::_detect = nullptr;

//识别人脸
int FaceDetect::facePredict(const Mat& src_image) {
    Mat face_test;
    int predict = 0;
    //截取的ROI人脸尺寸调整
//    if (src_image.rows >= 120)
//    {
        //改变图像大小，使用双线性差值
        resize(src_image, face_test, Size(92, 112));
//    }
    //判断是否正确检测ROI
    if (!face_test.empty())
    {
        //测试图像应该是灰度图
        predict = _detect->detectModel->predict(face_test);
    }
    cout << predict << endl;
    return predict;
}

int FaceDetect::detectFaceAndDraw( Mat& img,
                   double scale, bool detectEye )
{
    int i = 0, detectResult = 0;
    double t = 0;
    string faceName;
    //建立用于存放人脸的向量容器
    vector<Rect> faces;
    //定义一些颜色，用来标示不同的人脸
    const static Scalar colors[] =  {
        CV_RGB(0,0,255),
        CV_RGB(0,128,255),
        CV_RGB(0,255,255),
        CV_RGB(0,255,0),
        CV_RGB(255,128,0),
        CV_RGB(255,255,0),
        CV_RGB(255,0,0),
        CV_RGB(255,0,255)} ;
    //建立缩小的图片，加快检测速度
    Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );
    //转成灰度图像，Harr特征基于灰度图
    cvtColor( img, gray, CV_BGR2GRAY );
//    imshow("灰度",gray);
    //改变图像大小，使用双线性差值
    resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );
//    imshow("缩小尺寸",smallImg);
    //变换后的图像进行直方图均值化处理
    equalizeHist( smallImg, smallImg );
//    imshow("直方图均值处理",smallImg);
    //程序开始和结束插入此函数获取时间，经过计算求得算法执行时间
    t = (double)cvGetTickCount();
    //检测人脸
    /**detectMultiScale函数中smallImg表示的是要检测的输入图像为smallImg，faces表示检测到的人脸目标序列，1.1表示
    每次图像尺寸减小的比例为1.1，2表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大
    小都可以检测到人脸),CV_HAAR_SCALE_IMAGE表示不是缩放分类器来检测，而是缩放图像，Size(30, 30)为目标的
    最小最大尺寸**/
    _detect->faceCascade.detectMultiScale( smallImg, faces,
        1.1, 2, 0
//        |CV_HAAR_FIND_BIGGEST_OBJECT
//        |CV_HAAR_DO_ROUGH_SEARCH
        |CV_HAAR_SCALE_IMAGE
        ,Size(50, 50));

    t = (double)cvGetTickCount() - t;

    for (vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++ ) {
        //对识别到的每个人脸进行识别
        Mat smallImgROI = smallImg( *r );;
        vector<Rect> nestedObjects; //眼睛
        Point center;
        Scalar color = colors[i%8];
        int radius;

        double aspect_ratio = (double)r->width/r->height; //检测到的人脸比例
        //将缩小之前的图片缩放到原图像上
        if( 0.75 < aspect_ratio && aspect_ratio < 1.3 ) //符合条件的比例
        {
//            rectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)),
//                       cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)),
//                       color, 3, 8, 0);
            //对符合条件的人脸进行识别
            detectResult = facePredict(smallImgROI);
            switch (detectResult) {
                case 0:faceName = "BelingBeling"; break;
                default: faceName = "Error"; break;
            }
            rectangle( img, Point(cvRound(r->x*scale), cvRound(r->y*scale)),
                       Point(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)),
                       color, 3, 8, 0);
            putText(img, faceName, r->tl()*scale, FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));//添加文字

        }

        //////////////开启了眼睛识别/////////////
        if (detectEye && !_detect->eyeCascade.empty()) {
            _detect->eyeCascade.detectMultiScale( smallImgROI, nestedObjects,
                1.1, 2, 0
    //                |CASCADE_FIND_BIGGEST_OBJECT
    //                |CASCADE_DO_ROUGH_SEARCH
    //                |CASCADE_DO_CANNY_PRUNING
                |CASCADE_SCALE_IMAGE,
                Size(30, 30) );
            for ( size_t j = 0; j < nestedObjects.size(); j++ )
            {
                Rect nr = nestedObjects[j];
                center.x = cvRound((r->x + nr.x + nr.width*0.5)*scale);
                center.y = cvRound((r->y + nr.y + nr.height*0.5)*scale);
                radius = cvRound((nr.width + nr.height)*0.25*scale);
                circle( img, center, radius, color, 3, 8, 0 );
            }
        }
    }

    return detectResult;
}
